home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / doc / gpc / demos / crtdemo.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  34.1 KB  |  1,089 lines

  1. {
  2. GPC demo program for the CRT unit.
  3.  
  4. Copyright (C) 1999-2001 Free Software Foundation, Inc.
  5.  
  6. Author: Frank Heckenbach <frank@pascal.gnu.de>
  7.  
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation, version 2.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; see the file COPYING. If not, write to
  19. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.
  21.  
  22. As a special exception, if you incorporate even large parts of the
  23. code of this demo program into another program with substantially
  24. different functionality, this does not cause the other program to
  25. be covered by the GNU General Public License. This exception does
  26. not however invalidate any other reasons why it might be covered
  27. by the GNU General Public License.
  28. }
  29.  
  30. program CRTDemo;
  31.  
  32. uses GPC, CRT;
  33.  
  34. type
  35.   TFrameChars = array [1 .. 8] of Char;
  36.   TSimulateBlockCursorKind = (bc_None, bc_Blink, bc_Static);
  37.  
  38. const
  39.   SingleFrame : TFrameChars = (chCornerTLS, chLineHS, chCornerTRS, chLineVS, chLineVS, chCornerBLS, chLineHS, chCornerBRS);
  40.   DoubleFrame : TFrameChars = (chCornerTLD, chLineHD, chCornerTRD, chLineVD, chLineVD, chCornerBLD, chLineHD, chCornerBRD);
  41.  
  42. var
  43.   ScrollState : Boolean = True;
  44.   SimulateBlockCursorKind : TSimulateBlockCursorKind = bc_None;
  45.   CursorShape : TCursorShape = CursorNormal;
  46.   MainPanel : TPanel;
  47.   OrigScreenSize : TPoint;
  48.  
  49. procedure FrameWin (const Title : String; const Frame : TFrameChars; TitleInverse : Boolean);
  50. var
  51.   w, h, y, Color : Integer;
  52.   Attr : TTextAttr;
  53. begin
  54.   HideCursor;
  55.   SetPCCharSet (True);
  56.   ClrScr;
  57.   w := GetXMax;
  58.   h := GetYMax;
  59.   WriteCharAt (1, 1, 1,     Frame [1], TextAttr);
  60.   WriteCharAt (2, 1, w - 2, Frame [2], TextAttr);
  61.   WriteCharAt (w, 1, 1,     Frame [3], TextAttr);
  62.   for y := 2 to h - 1 do
  63.     begin
  64.       WriteCharAt (1, y, 1, Frame [4], TextAttr);
  65.       WriteCharAt (w, y, 1, Frame [5], TextAttr)
  66.     end;
  67.   WriteCharAt (1, h, 1,     Frame [6], TextAttr);
  68.   WriteCharAt (2, h, w - 2, Frame [7], TextAttr);
  69.   WriteCharAt (w, h, 1,     Frame [8], TextAttr);
  70.   SetPCCharSet (False);
  71.   Attr := TextAttr;
  72.   if TitleInverse then
  73.     begin
  74.       Color := GetTextColor;
  75.       TextColor (GetTextBackground);
  76.       TextBackground (Color)
  77.     end;
  78.   WriteStrAt ((w - Length (Title)) div 2 + 1, 1, Title, TextAttr);
  79.   TextAttr := Attr
  80. end;
  81.  
  82. function GetKey (TimeOut : Integer) = Key : TKey; forward;
  83.  
  84. procedure ClosePopUpWindow;
  85. begin
  86.   PanelDelete (GetActivePanel);
  87.   PanelDelete (GetActivePanel)
  88. end;
  89.  
  90. function PopUpConfirm (XSize, YSize : Integer; const Msg : String) : Boolean;
  91. var
  92.   ax, ay : Integer;
  93.   Key : TKey;
  94. begin
  95.   repeat
  96.     with ScreenSize do
  97.       begin
  98.         ax := (X - XSize - 4) div 2 + 1;
  99.         ay := (Y - YSize - 4) div 2 + 1
  100.       end;
  101.     PanelNew (ax, ay, ax + XSize + 3, ay + YSize + 1, False);
  102.     TextBackground (Black);
  103.     TextColor (Yellow);
  104.     SetControlChars (True);
  105.     FrameWin ('', DoubleFrame, False);
  106.     NormalCursor;
  107.     PanelNew (ax + 2, ay + 1, ax + XSize + 2, ay + YSize, False);
  108.     ClrScr;
  109.     Write (Msg);
  110.     Key := GetKey (- 1);
  111.     if Key = kbScreenSizeChanged then ClosePopUpWindow
  112.   until Key <> kbScreenSizeChanged;
  113.   PopUpConfirm := not (Key in [kbEsc, kbAltEsc])
  114. end;
  115.  
  116. procedure MainDraw;
  117. begin
  118.   Writeln ('3, F3  : Open a window');
  119.   Writeln ('4, F4  : Close a window');
  120.   Writeln ('5, F5  : Previous window');
  121.   Writeln ('6, F6  : Next window');
  122.   Writeln ('7, F7  : Move window');
  123.   Writeln ('8, F8  : Resize window');
  124.   Write   ('q, Esc : Quit')
  125. end;
  126.  
  127. procedure StatusDraw;
  128. const
  129.   YesNo : array [Boolean] of String [3] = ('No', 'Yes');
  130.   SimulateBlockCursorIDs : array [TSimulateBlockCursorKind] of String [8] = ('Off', 'Blinking', 'Static');
  131.   CursorShapeIDs : array [TCursorShape] of String [7] = ('Ignored', 'Hidden', 'Normal', 'Fat', 'Block');
  132. begin
  133.   Writeln ('You can change some of the following');
  134.   Writeln ('settings  by pressing the key  shown');
  135.   Writeln ('in parentheses. Naturally, color and');
  136.   Writeln ('changing the cursor  shape or screen');
  137.   Writeln ('size does not work on all terminals.');
  138.   Writeln;
  139.   Writeln ('XCurses version:          ', YesNo [XCRT]);
  140.   Writeln ('CRTSavePreviousScreen:    ', YesNo [CRTSavePreviousScreenWorks]);
  141.   Writeln ('(M)onochrome:             ', YesNo [IsMonochrome]);
  142.   with ScreenSize do
  143.     begin
  144.       Writeln ('Screen (C)olumns:         ', X);
  145.       Writeln ('Screen (L)ines:           ', Y);
  146.       Writeln ('(R)estore screen size');
  147.     end;
  148.   Writeln ('(B)reak checking:         ', YesNo [CheckBreak]);
  149.   Writeln ('(S)crolling:              ', YesNo [ScrollState]);
  150.   Writeln ('S(i)mulated block cursor: ', SimulateBlockCursorIDs [SimulateBlockCursorKind]);
  151.   Write   ('C(u)rsor shape:           ', CursorShapeIDs [CursorShape]);
  152.   GotoXY (36, WhereY)
  153. end;
  154.  
  155. procedure RedrawAll; forward;
  156. procedure CheckScreenSize; forward;
  157.  
  158. procedure StatusKey (Key : TKey);
  159. var NewSize : TPoint;
  160. begin
  161.   case LoCase (Key2Char (Key)) of
  162.     'm' : begin
  163.             SetMonochrome (not IsMonochrome);
  164.             RedrawAll
  165.           end;
  166.     'c' : with ScreenSize do
  167.             begin
  168.               if X > 40 then
  169.                 NewSize.X := 40
  170.               else
  171.                 NewSize.X := 80;
  172.               if Y > 25 then
  173.                 NewSize.Y := 50
  174.               else
  175.                 NewSize.Y := 25;
  176.               SetScreenSize (NewSize.X, NewSize.Y);
  177.               CheckScreenSize
  178.             end;
  179.     'l' : with ScreenSize do
  180.             begin
  181.               if X > 40 then
  182.                 NewSize.X := 80
  183.               else
  184.                 NewSize.X := 40;
  185.               if Y > 25 then
  186.                 NewSize.Y := 25
  187.               else
  188.                 NewSize.Y := 50;
  189.               SetScreenSize (NewSize.X, NewSize.Y);
  190.               CheckScreenSize
  191.             end;
  192.     'r' : begin
  193.             SetScreenSize (OrigScreenSize.X, OrigScreenSize.Y);
  194.             CheckScreenSize
  195.           end;
  196.     'b' : CheckBreak := not CheckBreak;
  197.     's' : ScrollState := not ScrollState;
  198.     'i' : if SimulateBlockCursorKind = High (SimulateBlockCursorKind) then
  199.             SimulateBlockCursorKind := Low (SimulateBlockCursorKind)
  200.           else
  201.             Inc (SimulateBlockCursorKind);
  202.     'u' : begin
  203.             case CursorShape of
  204.               CursorNormal : CursorShape := CursorBlock;
  205.               CursorFat,
  206.               CursorBlock  : CursorShape := CursorHidden;
  207.               else           CursorShape := CursorNormal
  208.             end
  209.           end;
  210.   end;
  211.   ClrScr;
  212.   StatusDraw
  213. end;
  214.  
  215. procedure TextAttrDemo;
  216. const HexDigits : array [0 .. $f] of Char = '0123456789ABCDEF';
  217. var f, b, y, x1, y1, x2, y2, Fill, n1, n2, n3 : Integer;
  218. begin
  219.   GetWindow (x1, y1, x2, y2);
  220.   Window (x1 - 1, y1, x2, y2);
  221.   TextColor (White);
  222.   TextBackground (Blue);
  223.   ClrScr;
  224.   SetScroll (False);
  225.   Fill := GetXMax - 32;
  226.   for y := 1 to GetYMax do
  227.     begin
  228.       GotoXY (1, y);
  229.       b := (y - 1) mod 16;
  230.       n1 := 0;
  231.       for f := 0 to 15 do
  232.         begin
  233.           TextAttr := f + 16 * b;
  234.           n2 := (Fill * (1 + 2 * f) + 16) div 32;
  235.           n3 := (Fill * (2 + 2 * f) + 16) div 32;
  236.           Write ('' : n2 - n1, HexDigits [b], HexDigits [f], '' : n3 - n2);
  237.           n1 := n3
  238.         end
  239.     end
  240. end;
  241.  
  242. procedure CharSetDemo (UsePCCharSet : Boolean);
  243. var h, l, y, x1, y1, x2, y2, Fill, n1, n2 : Integer;
  244. begin
  245.   GetWindow (x1, y1, x2, y2);
  246.   Window (x1 - 1, y1, x2, y2);
  247.   ClrScr;
  248.   SetScroll (False);
  249.   SetPCCharSet (UsePCCharSet);
  250.   SetControlChars (False);
  251.   Fill := GetXMax - 35;
  252.   for y := 1 to GetYMax do
  253.     begin
  254.       GotoXY (1, y);
  255.       h := (y - 2) mod 16;
  256.       n1 := (Fill + 9) div 18;
  257.       if y = 1 then
  258.         Write ('' : 3 + n1)
  259.       else
  260.         Write (16 * h : 3 + n1);
  261.       for l := 0 to 15 do
  262.         begin
  263.           n2 := (Fill * (2 + l) + 9) div 18;
  264.           if y = 1 then
  265.             Write ('' : n2 - n1, l : 2)
  266.           else
  267.             Write ('' : n2 - n1 + 1, Chr (16 * h + l));
  268.           n1 := n2
  269.         end
  270.     end
  271. end;
  272.  
  273. procedure NormalCharSetDemo;
  274. begin
  275.   CharSetDemo (False)
  276. end;
  277.  
  278. procedure PCCharSetDemo;
  279. begin
  280.   CharSetDemo (True)
  281. end;
  282.  
  283. procedure FKeyDemoDraw;
  284. var x1, y1, x2, y2 : Integer;
  285. begin
  286.   GetWindow (x1, y1, x2, y2);
  287.   Window (x1, y1, x2 - 1, y2);
  288.   ClrScr;
  289.   SetScroll (False);
  290.   Writeln ('You can type the following keys');
  291.   Writeln ('(function keys if present on the');
  292.   Writeln ('terminal, letters as alternatives):');
  293.   Writeln ('S, Left      : left (wrap-around)');
  294.   Writeln ('D, Right     : right (wrap-around)');
  295.   Writeln ('E, Up        : up (wrap-around)');
  296.   Writeln ('X, Down      : down (wrap-around)');
  297.   Writeln ('A, Home      : go to first column');
  298.   Writeln ('F, End       : go to last column');
  299.   Writeln ('R, Page Up   : go to first line');
  300.   Writeln ('C, Page Down : go to last line');
  301.   Writeln ('Y, Ctrl-PgUp : first column and line');
  302.   GotoXY (1, 13);
  303.   Writeln ('B, Ctrl-PgDn : last column and line');
  304.   Writeln ('Z, Ctrl-Home : clear screen');
  305.   Writeln ('N, Ctrl-End  : clear to end of line');
  306.   Writeln ('V, Insert    : insert a line');
  307.   Writeln ('T, Delete    : delete a line');
  308.   Writeln ('#            : beep');
  309.   Writeln ('*            : flash');
  310.   Writeln ('Tab, Enter, Backspace, other normal');
  311.   Writeln ('  characters : write text')
  312. end;
  313.  
  314. procedure FKeyDemoKey (Key : TKey);
  315. const TabSize = 8;
  316. var
  317.   Ch : Char;
  318.   NewX : Integer;
  319. begin
  320.   case LoCaseKey (Key) of
  321.     Ord ('s'), kbLeft     : if WhereX = 1 then GotoXY (GetXMax, WhereY) else GotoXY (WhereX - 1, WhereY);
  322.     Ord ('d'), kbRight    : if WhereX = GetXMax then GotoXY (1, WhereY) else GotoXY (WhereX + 1, WhereY);
  323.     Ord ('e'), kbUp       : if WhereY = 1 then GotoXY (WhereX, GetYMax) else GotoXY (WhereX, WhereY - 1);
  324.     Ord ('x'), kbDown     : if WhereY = GetYMax then GotoXY (WhereX, 1) else GotoXY (WhereX, WhereY + 1);
  325.     Ord ('a'), kbHome     : Write (chCR);
  326.     Ord ('f'), kbEnd      : GotoXY (GetXMax, WhereY);
  327.     Ord ('r'), kbPgUp     : GotoXY (WhereX, 1);
  328.     Ord ('c'), kbPgDn     : GotoXY (WhereX, GetYMax);
  329.     Ord ('y'), kbCtrlPgUp : GotoXY (1, 1);
  330.     Ord ('b'), kbCtrlPgDn : GotoXY (GetXMax, GetYMax);
  331.     Ord ('z'), kbCtrlHome : ClrScr;
  332.     Ord ('n'), kbCtrlEnd  : ClrEOL;
  333.     Ord ('v'), kbIns      : InsLine;
  334.     Ord ('t'), kbDel      : DelLine;
  335.     Ord ('#')             : Beep;
  336.     Ord ('*')             : Flash;
  337.     kbTab                 : begin
  338.                               NewX := ((WhereX - 1) div TabSize + 1) * TabSize + 1;
  339.                               if NewX <= GetXMax then GotoXY (NewX, WhereY) else Writeln
  340.                             end;
  341.     kbCR                  : Writeln;
  342.     kbBkSp                : Write (chBkSp, ' ', chBkSp);
  343.     else                    Ch := Key2Char (Key);
  344.                             if Ch <> #0 then Write (Ch)
  345.   end
  346. end;
  347.  
  348. procedure KeyDemoDraw;
  349. begin
  350.   Writeln ('Press some keys...')
  351. end;
  352.  
  353. procedure KeyDemoKey (Key : TKey);
  354. var Ch : Char;
  355. begin
  356.   Ch := Key2Char (Key);
  357.   if Ch <> #0 then
  358.     begin
  359.       Write ('Normal key');
  360.       if Ch in [' ' .. #126] then Write (' `', Ch, '''');
  361.       Writeln (', ASCII #', Ord (Ch))
  362.     end
  363.   else
  364.     Writeln ('Special key ', Ord (Key2Scan (Key)))
  365. end;
  366.  
  367. procedure IOSelectPeriodical;
  368. var
  369.   CurrentTime : TimeStamp;
  370.   s : String (8);
  371.   i : Integer;
  372. begin
  373.   GetTimeStamp (CurrentTime);
  374.   with CurrentTime do
  375.     WriteStr (s, Hour : 2, ':', Minute : 2, ':', Second : 2);
  376.   for i := 1 to Length (s) do
  377.     if s [i] = ' ' then s [i] := '0';
  378.   GotoXY (1, 12);
  379.   Write ('The time is: ', s)
  380. end;
  381.  
  382. procedure IOSelectDraw;
  383. begin
  384.   Writeln ('IOSelect is a way to handle I/O from');
  385.   Writeln ('or to several places simultaneously,');
  386.   Writeln ('without  having  to use  threads  or');
  387.   Writeln ('signal/interrupt  handlers  or waste');
  388.   Writeln ('CPU time with busy waiting.');
  389.   Writeln;
  390.   Writeln ('This demo  shows how  IOSelect works');
  391.   Writeln ('in connection with CRT.  It displays');
  392.   Writeln ('a clock,  but still  reacts  to user');
  393.   Writeln ('input immediately.');
  394.   IOSelectPeriodical
  395. end;
  396.  
  397. procedure ModifierPeriodical;
  398. const
  399.   Pressed : array [Boolean] of String [8] = ('Released', 'Pressed');
  400.   ModifierNames : array [1 .. 7] of record
  401.     Modifier : Integer;
  402.     Name     : String (17)
  403.   end =
  404.    ((shLeftShift,  'Left Shift'),
  405.     (shRightShift, 'Right Shift'),
  406.     (shLeftCtrl,   'Left Control'),
  407.     (shRightCtrl,  'Right Control'),
  408.     (shAlt,        'Alt (left)'),
  409.     (shAltGr,      'AltGr (right Alt)'),
  410.     (shExtra,      'Extra'));
  411. var
  412.   ShiftState, i : Integer;
  413. begin
  414.   ShiftState := GetShiftState;
  415.   for i := 1 to 7 do
  416.     with ModifierNames [i] do
  417.       begin
  418.         GotoXY (1, 4 + i);
  419.         ClrEOL;
  420.         Write (Name, ':');
  421.         GotoXY (20, WhereY);
  422.         Write (Pressed [ShiftState and Modifier <> 0])
  423.       end
  424. end;
  425.  
  426. procedure ModifierDraw;
  427. begin
  428.   Writeln ('Modifier keys (NOTE: only');
  429.   Writeln ('available on some systems;');
  430.   Writeln ('X11: only after key press):');
  431.   ModifierPeriodical
  432. end;
  433.  
  434. procedure ChecksDraw;
  435. begin
  436.   Writeln ('(O)S shell');
  437.   Writeln ('OS shell with (C)learing');
  438.   Writeln ('(R)efresh check');
  439.   Write   ('(S)ound check')
  440. end;
  441.  
  442. procedure ChecksKey (Key : TKey);
  443. var
  444.   i, j : Integer;
  445.   Dummy : volatile Real;
  446.  
  447.   procedure DoOSShell;
  448.   var
  449.     Result : Integer;
  450.     Shell : TString;
  451.     Dummy : TKey;
  452.   begin
  453.     Shell := GetShellPath (null);
  454.     {$I-}
  455.     Result := Execute (Shell);
  456.     {$I+}
  457.     if (InOutRes <> 0) or (Result <> 0) then
  458.       begin
  459.         ClrScr;
  460.         if InOutRes <> 0 then
  461.           Writeln (GetIOErrorMessage, ' while trying to execute `', Shell, '''.')
  462.         else
  463.           Writeln ('`', Shell, ''' returned status ', Result, '.');
  464.         Write ('Any key to continue.');
  465.         BlockCursor;
  466.         Dummy := GetKey (- 1)
  467.       end
  468.   end;
  469.  
  470. begin
  471.   case LoCase (Key2Char (Key)) of
  472.     'o' : begin
  473.             if PopUpConfirm (36, 12, 'You will now get an OS shell. Unless' + NewLine +
  474.                                      'CRTDemo is running  in its own (GUI)' + NewLine +
  475.                                      'window,  the shell  will run  on the' + NewLine +
  476.                                      'same screen as CRTDemo  which is not' + NewLine +
  477.                                      'cleared before the shell is started.' + NewLine +
  478.                                      'If possible, the screen contents are' + NewLine +
  479.                                      'restored to the state before CRTDemo' + NewLine +
  480.                                      'was started. After leaving the shell' + NewLine +
  481.                                      'in the usual way (usually  by enter-' + NewLine +
  482.                                      'ing  `exit''), you will  get back to' + NewLine +
  483.                                      'the demo.  <ESC> to abort, any other' + NewLine +
  484.                                      'key to start.') then
  485.               begin
  486.                 RestoreTerminal (True);
  487.                 DoOSShell
  488.               end;
  489.             ClosePopUpWindow
  490.           end;
  491.     'c' : begin
  492.             if PopUpConfirm (36, 9, 'You will now get an OS shell. Unless' + NewLine +
  493.                                     'CRTDemo is running in  its own (GUI)' + NewLine +
  494.                                     'window, the screen  will be cleared,' + NewLine +
  495.                                     'and the cursor will be  moved to the' + NewLine +
  496.                                     'top  before  the  shell  is started.' + NewLine +
  497.                                     'After leaving the shell in the usual' + NewLine +
  498.                                     'way  (usually  by entering  `exit''),' + NewLine +
  499.                                     'you will get back to the demo. <ESC>' + NewLine +
  500.                                     'to abort, any other key to start.') then
  501.               begin
  502.                 RestoreTerminalClearCRT;
  503.                 DoOSShell
  504.               end;
  505.             ClosePopUpWindow
  506.           end;
  507.     'r' : begin
  508.             if PopUpConfirm (36, 11, 'The program will  now get  busy with' + NewLine +
  509.                                      'some  dummy  computations.  However,' + NewLine +
  510.                                      'CRT output in  the form of dots will' + NewLine +
  511.                                      'still appear continuously one by one' + NewLine +
  512.                                      '(rather than the  whole line at once' + NewLine +
  513.                                      'in the end). While running, the test' + NewLine +
  514.                                      'cannot  be  interrupted.   <ESC>  to' + NewLine +
  515.                                      'abort, any other key to start.') then
  516.               begin
  517.                 SetCRTUpdate (UpdateRegularly);
  518.                 BlockCursor;
  519.                 Writeln;
  520.                 Writeln;
  521.                 for i := 1 to GetXMax - 2 do
  522.                   begin
  523.                     Write ('.');
  524.                     for j := 1 to 400000 do Dummy := Random
  525.                   end;
  526.                 SetCRTUpdate (UpdateInput);
  527.                 Writeln;
  528.                 Write ('Press any key.');
  529.                 Dummy := GetKey (- 1)
  530.               end;
  531.             ClosePopUpWindow
  532.           end;
  533.     's' : begin
  534.             if PopUpConfirm (32, 4, 'You will now hear some sounds if' + NewLine +
  535.                                     'supported  (otherwise there will' + NewLine +
  536.                                     'just be a short pause). <ESC> to' + NewLine +
  537.                                     'abort, any other key to start.') then
  538.               begin
  539.                 BlockCursor;
  540.                 for i := 0 to 7 do
  541.                   begin
  542.                     Sound (Round (440 * 2 ** (Round (i * 12 / 7 + 0.3) / 12)));
  543.                     if GetKey (400000) in [kbEsc, kbAltEsc] then Break
  544.                   end;
  545.                 NoSound
  546.               end;
  547.             ClosePopUpWindow
  548.           end;
  549.   end
  550. end;
  551.  
  552. type
  553.   PWindowList = ^TWindowList;
  554.   TWindowList = record
  555.     Next, Prev : PWindowList;
  556.     Panel, FramePanel : TPanel;
  557.     WindowType : Integer;
  558.     x1, y1, xs, ys : Integer;
  559.     State : (ws_None, ws_Moving, ws_Resizing);
  560.   end;
  561.  
  562.   TKeyProc = procedure (Key : TKey);
  563.   TProcedure = procedure;
  564.  
  565. const
  566.   MenuNameLength = 16;
  567.   WindowTypes  : array [0 .. 9] of record
  568.     DrawProc,
  569.     PeriodicalProc : procedure;
  570.     KeyProc        : TKeyProc;
  571.     Name           : String (MenuNameLength);
  572.     Color,
  573.     Background,
  574.     MinSizeX,
  575.     MinSizeY,
  576.     PrefSizeX,
  577.     PrefSizeY      : Integer;
  578.     RedrawAlways,
  579.     WantCursor     : Boolean
  580.   end =
  581.   ((MainDraw         , nil               , nil        , 'CRT Demo'        , LightGreen, Blue     , 26,  7,  0,  0, False, False),
  582.    (StatusDraw       , nil               , StatusKey  , 'Status'          , White     , Red      , 38, 16,  0,  0, True,  True),
  583.    (TextAttrDemo     , nil               , nil        , 'Text Attributes' , White     , Blue     , 32, 16, 64, 16, False, False),
  584.    (NormalCharSetDemo, nil               , nil        , 'Character Set'   , Black     , Green    , 35, 17, 53, 17, False, False),
  585.    (PCCharSetDemo    , nil               , nil        , 'PC Character Set', Black     , Brown    , 35, 17, 53, 17, False, False),
  586.    (KeyDemoDraw      , nil               , KeyDemoKey , 'Keys'            , Blue      , LightGray, 29,  5, -1, -1, False, True),
  587.    (FKeyDemoDraw     , nil               , FKeyDemoKey, 'Function Keys'   , Blue      , LightGray, 38, 22, -1, -1, False, True),
  588.    (ModifierDraw     , ModifierPeriodical, nil        , 'Modifier Keys'   , Black     , Cyan     , 29, 11,  0,  0, True,  False),
  589.    (IOSelectDraw     , IOSelectPeriodical, nil        , 'IOSelect Demo'   , White     , Magenta  , 38, 12,  0,  0, False, False),
  590.    (ChecksDraw       , nil               , ChecksKey  , 'Various Checks'  , Black     , Red      , 26,  4,  0,  0, False, False));
  591.  
  592.   MenuMax = High (WindowTypes);
  593.   MenuXSize = MenuNameLength + 4;
  594.   MenuYSize = MenuMax + 2;
  595.  
  596. var
  597.   WindowList : PWindowList = nil;
  598.  
  599. procedure RedrawFrame (p : PWindowList);
  600. begin
  601.   with p^, WindowTypes [WindowType] do
  602.     begin
  603.       PanelActivate (FramePanel);
  604.       Window (x1, y1, x1 + xs - 1, y1 + ys - 1);
  605.       ClrScr;
  606.       case State of
  607.         ws_None     : if p = WindowList
  608.                         then FrameWin (' ' + Name + ' ', DoubleFrame, True)
  609.                         else FrameWin (' ' + Name + ' ', SingleFrame, False);
  610.         ws_Moving   : FrameWin (' Move Window ', SingleFrame, True);
  611.         ws_Resizing : FrameWin (' Resize Window ', SingleFrame, True);
  612.       end
  613.     end
  614. end;
  615.  
  616. procedure DrawWindow (p : PWindowList);
  617. begin
  618.   with p^, WindowTypes [WindowType] do
  619.     begin
  620.       RedrawFrame (p);
  621.       PanelActivate (Panel);
  622.       Window (x1 + 2, y1 + 1, x1 + xs - 2, y1 + ys - 2);
  623.       ClrScr;
  624.       DrawProc
  625.     end
  626. end;
  627.  
  628. procedure RedrawAll;
  629. var
  630.   LastPanel : TPanel;
  631.   p : PWindowList;
  632.   x2, y2 : Integer;
  633. begin
  634.   LastPanel := GetActivePanel;
  635.   PanelActivate (MainPanel);
  636.   TextBackground (Blue);
  637.   ClrScr;
  638.   p := WindowList;
  639.   if p <> nil then
  640.     repeat
  641.       with p^ do
  642.         begin
  643.           PanelActivate (FramePanel);
  644.           GetWindow (x1, y1, x2, y2); { updated automatically by CRT }
  645.           xs := x2 - x1 + 1;
  646.           ys := y2 - y1 + 1
  647.         end;
  648.       DrawWindow (p);
  649.       p := p^.Next
  650.     until p = WindowList;
  651.   PanelActivate (LastPanel)
  652. end;
  653.  
  654. procedure CheckScreenSize;
  655. var
  656.   LastPanel : TPanel;
  657.   MinScreenSizeX, MinScreenSizeY, i : Integer;
  658. begin
  659.   LastPanel := GetActivePanel;
  660.   PanelActivate (MainPanel);
  661.   HideCursor;
  662.   MinScreenSizeX := MenuXSize;
  663.   MinScreenSizeY := MenuYSize;
  664.   for i := Low (WindowTypes) to High (WindowTypes) do
  665.     with WindowTypes [i] do
  666.       begin
  667.         MinScreenSizeX := Max (MinScreenSizeX, MinSizeX + 2);
  668.         MinScreenSizeY := Max (MinScreenSizeY, MinSizeY + 2)
  669.       end;
  670.   with ScreenSize do
  671.     begin
  672.       Window (1, 1, X, Y);
  673.       if (X < MinScreenSizeX) or (Y < MinScreenSizeY) then
  674.         begin
  675.           NormVideo;
  676.           ClrScr;
  677.           RestoreTerminal (True);
  678.           Writeln (StdErr, 'Sorry, your screen is too small for this demo (', X, 'x', Y, ').');
  679.           Writeln (StdErr, 'You need at least ', MinScreenSizeX, 'x', MinScreenSizeY, ' characters.');
  680.           Halt (2)
  681.         end
  682.     end;
  683.   PanelActivate (LastPanel);
  684.   RedrawAll
  685. end;
  686.  
  687. procedure Die; attribute (noreturn);
  688. procedure Die;
  689. begin
  690.   NoSound;
  691.   RestoreTerminalClearCRT;
  692.   Writeln (StdErr, 'You''re trying to kill me. Since I have break checking turned off,');
  693.   Writeln (StdErr, 'I''m not dying, but I''ll do you a favour and terminate now.');
  694.   Halt (3)
  695. end;
  696.  
  697. function GetKey (TimeOut : Integer) = Key : TKey;
  698. var
  699.   NeedSelect, SelectValue : Integer;
  700.   SimulateBlockCursorCurrent : TSimulateBlockCursorKind;
  701.   SelectInput : array [1 .. 1] of PAnyFile;
  702.   NextSelectTime : static MicroSecondTimeType = 0;
  703.   TimeOutTime : MicroSecondTimeType;
  704.   LastPanel : TPanel;
  705.   p : PWindowList;
  706. begin
  707.   LastPanel := GetActivePanel;
  708.   if TimeOut < 0
  709.     then TimeOutTime := High (TimeOutTime)
  710.     else TimeOutTime := GetMicroSecondTime + TimeOut;
  711.   NeedSelect := 0;
  712.   if TimeOut >= 0 then
  713.     Inc (NeedSelect);
  714.   SimulateBlockCursorCurrent := SimulateBlockCursorKind;
  715.   if SimulateBlockCursorCurrent <> bc_None then
  716.     Inc (NeedSelect);
  717.   p := WindowList;
  718.   repeat
  719.     if @WindowTypes [p^.WindowType].PeriodicalProc <> nil then
  720.       Inc (NeedSelect);
  721.     p := p^.Next
  722.   until p = WindowList;
  723.   p := WindowList;
  724.   repeat
  725.     with p^, WindowTypes [WindowType] do
  726.       if RedrawAlways then
  727.         begin
  728.           PanelActivate (Panel);
  729.           ClrScr;
  730.           DrawProc
  731.         end;
  732.     p := p^.Next
  733.   until p = WindowList;
  734.   if NeedSelect <> 0 then
  735.     repeat
  736.       CRTUpdate;
  737.       (*@@constarray1*)SelectInput [1] := ((*@@*)PAnyFile( @Input));
  738.       SelectValue := IOSelectRead (SelectInput, Max (0, Min (NextSelectTime, TimeOutTime) - GetMicroSecondTime));
  739.       if SelectValue = 0 then
  740.         begin
  741.           case SimulateBlockCursorCurrent of
  742.             bc_None   : ;
  743.             bc_Blink  : SimulateBlockCursor;
  744.             bc_Static : begin
  745.                           SimulateBlockCursor;
  746.                           SimulateBlockCursorCurrent := bc_None;
  747.                           Dec (NeedSelect)
  748.                         end
  749.           end;
  750.           NextSelectTime := GetMicroSecondTime + 120000;
  751.           p := WindowList;
  752.           repeat
  753.             with p^, WindowTypes [WindowType] do
  754.               if @PeriodicalProc <> nil then
  755.                 begin
  756.                   PanelActivate (Panel);
  757.                   PeriodicalProc
  758.                 end;
  759.             p := p^.Next
  760.           until p = WindowList
  761.         end;
  762.     until (NeedSelect = 0) or (SelectValue <> 0) or ((TimeOut >= 0) and (GetMicroSecondTime >= TimeOutTime));
  763.   if NeedSelect = 0 then
  764.     SelectValue := 1;
  765.   if SelectValue = 0
  766.     then Key := 0
  767.     else Key := ReadKeyWord;
  768.   if SimulateBlockCursorKind <> bc_None then
  769.     SimulateBlockCursorOff;
  770.   if IsDeadlySignal (Key) then Die;
  771.   if Key = kbScreenSizeChanged then CheckScreenSize;
  772.   PanelActivate (LastPanel)
  773. end;
  774.  
  775. function Menu = n : Integer;
  776. var
  777.   i, ax, ay : Integer;
  778.   Key : TKey;
  779.   Done : Boolean;
  780. begin
  781.   n := 1;
  782.   repeat
  783.     with ScreenSize do
  784.       begin
  785.         ax := (X - MenuXSize) div 2 + 1;
  786.         ay := (Y - MenuYSize) div 2 + 1
  787.       end;
  788.     PanelNew (ax, ay, ax + MenuXSize - 1, ay + MenuYSize - 1, False);
  789.     SetControlChars (True);
  790.     TextColor (Blue);
  791.     TextBackground (LightGray);
  792.     FrameWin (' Select Window ', DoubleFrame, True);
  793.     IgnoreCursor;
  794.     PanelNew (ax + 1, ay + 1, ax + MenuXSize - 2, ay + MenuYSize - 2, False);
  795.     ClrScr;
  796.     TextColor (Black);
  797.     SetScroll (False);
  798.     Done := False;
  799.     repeat
  800.       for i := 1 to MenuMax do
  801.         begin
  802.           GotoXY (1, i);
  803.           if i = n
  804.             then TextBackGround (Green)
  805.             else TextBackGround (LightGray);
  806.           ClrEOL;
  807.           Write (' ', WindowTypes [i].Name);
  808.           ChangeTextAttr (2, i, 1, Red + $10 * GetTextBackground)
  809.         end;
  810.       Key := GetKey (- 1);
  811.       case LoCaseKey (Key) of
  812.         kbUp                   : if n = 1 then n := MenuMax else Dec (n);
  813.         kbDown                 : if n = MenuMax then n := 1 else Inc (n);
  814.         kbHome,
  815.         kbPgUp,
  816.         kbCtrlPgUp,
  817.         kbCtrlHome             : n := 1;
  818.         kbEnd,
  819.         kbPgDn,
  820.         kbCtrlPgDn,
  821.         kbCtrlEnd              : n := MenuMax;
  822.         kbCR                   : Done := True;
  823.         kbEsc, kbAltEsc        : begin
  824.                                    n := - 1;
  825.                                    Done := True
  826.                                  end;
  827.         Ord ('a') .. Ord ('z') : begin
  828.                                    i := MenuMax;
  829.                                    while (i > 0) and (LoCase (Key2Char (Key)) <> LoCase (WindowTypes [i].Name [1])) do Dec (i);
  830.                                    if i > 0 then
  831.                                      begin
  832.                                        n := i;
  833.                                        Done := True
  834.                                      end
  835.                                  end;
  836.       end
  837.     until Done or (Key = kbScreenSizeChanged);
  838.     ClosePopUpWindow
  839.   until Key <> kbScreenSizeChanged
  840. end;
  841.  
  842. procedure NewWindow (WindowType, ax, ay : Integer);
  843. var
  844.   p, LastWindow : PWindowList;
  845.   MaxX1, MaxY1 : Integer;
  846. begin
  847.   New (p);
  848.   if WindowList = nil then
  849.     begin
  850.       p^.Prev := p;
  851.       p^.Next := p
  852.     end
  853.   else
  854.     begin
  855.       p^.Prev := WindowList;
  856.       p^.Next := WindowList^.Next;
  857.       p^.Prev^.Next := p;
  858.       p^.Next^.Prev := p;
  859.     end;
  860.   p^.WindowType := WindowType;
  861.   with p^, WindowTypes [WindowType] do
  862.     begin
  863.       with ScreenSize do
  864.         begin
  865.           if PrefSizeX > 0 then xs := PrefSizeX else xs := MinSizeX;
  866.           if PrefSizeY > 0 then ys := PrefSizeY else ys := MinSizeY;
  867.           xs := Min (xs + 2, X);
  868.           ys := Min (ys + 2, Y);
  869.           MaxX1 := X - xs + 1;
  870.           MaxY1 := Y - ys + 1;
  871.           if ax = 0 then x1 := Random (MaxX1) + 1 else x1 := Min (ax, MaxX1);
  872.           if ay = 0 then y1 := Random (MaxY1) + 1 else y1 := Min (ay, MaxY1);
  873.           if (ax = 0) and (PrefSizeX < 0) then Inc (xs, Random (X - x1 - xs + 2));
  874.           if (ax = 0) and (PrefSizeY < 0) then Inc (ys, Random (Y - y1 - ys + 2))
  875.         end;
  876.       State := ws_None;
  877.       PanelNew (1, 1, 1, 1, False);
  878.       FramePanel := GetActivePanel;
  879.       SetControlChars (True);
  880.       TextColor (Color);
  881.       TextBackground (Background);
  882.       PanelNew (1, 1, 1, 1, False);
  883.       SetPCCharSet (False);
  884.       Panel := GetActivePanel;
  885.     end;
  886.   LastWindow := WindowList;
  887.   WindowList := p;
  888.   if LastWindow <> nil then RedrawFrame (LastWindow);
  889.   DrawWindow (p)
  890. end;
  891.  
  892. procedure OpenWindow;
  893. var WindowType : Integer;
  894. begin
  895.   WindowType := Menu;
  896.   if WindowType >= 0 then NewWindow (WindowType, 0, 0)
  897. end;
  898.  
  899. procedure NextWindow;
  900. var LastWindow : PWindowList;
  901. begin
  902.   LastWindow := WindowList;
  903.   WindowList := WindowList^.Next;
  904.   PanelTop (WindowList^.FramePanel);
  905.   PanelTop (WindowList^.Panel);
  906.   RedrawFrame (LastWindow);
  907.   RedrawFrame (WindowList)
  908. end;
  909.  
  910. procedure PreviousWindow;
  911. var LastWindow : PWindowList;
  912. begin
  913.   PanelMoveAbove (WindowList^.Panel, MainPanel);
  914.   PanelMoveAbove (WindowList^.FramePanel, MainPanel);
  915.   LastWindow := WindowList;
  916.   WindowList := WindowList^.Prev;
  917.   RedrawFrame (LastWindow);
  918.   RedrawFrame (WindowList)
  919. end;
  920.  
  921. procedure CloseWindow;
  922. var p : PWindowList;
  923. begin
  924.   if WindowList^.WindowType <> 0 then
  925.     begin
  926.       p := WindowList;
  927.       NextWindow;
  928.       PanelDelete (p^.FramePanel);
  929.       PanelDelete (p^.Panel);
  930.       p^.Next^.Prev := p^.Prev;
  931.       p^.Prev^.Next := p^.Next;
  932.       Dispose (p)
  933.     end
  934. end;
  935.  
  936. procedure MoveWindow;
  937. var Done, Changed : Boolean;
  938. begin
  939.   with WindowList^ do
  940.     begin
  941.       Done := False;
  942.       Changed := True;
  943.       State := ws_Moving;
  944.       repeat
  945.         if Changed then DrawWindow (WindowList);
  946.         Changed := True;
  947.         case LoCaseKey (GetKey (- 1)) of
  948.           Ord ('s'), kbLeft     : if x1 > 1 then Dec (x1);
  949.           Ord ('d'), kbRight    : if x1 + xs - 1 < ScreenSize.X then Inc (x1);
  950.           Ord ('e'), kbUp       : if y1 > 1 then Dec (y1);
  951.           Ord ('x'), kbDown     : if y1 + ys - 1 < ScreenSize.Y then Inc (y1);
  952.           Ord ('a'), kbHome     : x1 := 1;
  953.           Ord ('f'), kbEnd      : x1 := ScreenSize.X - xs + 1;
  954.           Ord ('r'), kbPgUp     : y1 := 1;
  955.           Ord ('c'), kbPgDn     : y1 := ScreenSize.Y - ys + 1;
  956.           Ord ('y'), kbCtrlPgUp : begin
  957.                                     x1 := 1;
  958.                                     y1 := 1
  959.                                   end;
  960.           Ord ('b'), kbCtrlPgDn : with ScreenSize do
  961.                                     begin
  962.                                       x1 := X - xs + 1;
  963.                                       y1 := Y - ys + 1
  964.                                     end;
  965.           kbCR,
  966.           kbEsc, kbAltEsc       : Done := True;
  967.           else                    Changed := False
  968.         end
  969.       until Done;
  970.       State := ws_None;
  971.       DrawWindow (WindowList)
  972.     end
  973. end;
  974.  
  975. procedure ResizeWindow;
  976. var Done, Changed : Boolean;
  977. begin
  978.   with WindowList^, WindowTypes [WindowType] do
  979.     begin
  980.       Done := False;
  981.       Changed := True;
  982.       State := ws_Resizing;
  983.       repeat
  984.         if Changed then DrawWindow (WindowList);
  985.         Changed := True;
  986.         case LoCaseKey (GetKey (- 1)) of
  987.           Ord ('s'), kbLeft     : if xs > MinSizeX + 2 then Dec (xs);
  988.           Ord ('d'), kbRight    : if x1 + xs - 1 < ScreenSize.X then Inc (xs);
  989.           Ord ('e'), kbUp       : if ys > MinSizeY + 2 then Dec (ys);
  990.           Ord ('x'), kbDown     : if y1 + ys - 1 < ScreenSize.Y then Inc (ys);
  991.           Ord ('a'), kbHome     : xs := MinSizeX + 2;
  992.           Ord ('f'), kbEnd      : xs := ScreenSize.X - x1 + 1;
  993.           Ord ('r'), kbPgUp     : ys := MinSizeY + 2;
  994.           Ord ('c'), kbPgDn     : ys := ScreenSize.Y - y1 + 1;
  995.           Ord ('y'), kbCtrlPgUp : begin
  996.                                     xs := MinSizeX + 2;
  997.                                     ys := MinSizeY + 2
  998.                                   end;
  999.           Ord ('b'), kbCtrlPgDn : with ScreenSize do
  1000.                                     begin
  1001.                                       xs := X - x1 + 1;
  1002.                                       ys := Y - y1 + 1
  1003.                                     end;
  1004.           kbCR,
  1005.           kbEsc, kbAltEsc       : Done := True;
  1006.           else                    Changed := False
  1007.         end
  1008.       until Done;
  1009.       State := ws_None;
  1010.       DrawWindow (WindowList)
  1011.     end
  1012. end;
  1013.  
  1014. procedure ActivateCursor;
  1015. begin
  1016.   with WindowList^, WindowTypes [WindowType] do
  1017.     begin
  1018.       PanelActivate (Panel);
  1019.       if WantCursor
  1020.         then SetCursorShape (CursorShape)
  1021.         else HideCursor
  1022.     end;
  1023.   SetScroll (ScrollState)
  1024. end;
  1025.  
  1026. var
  1027.   Key : TKey;
  1028.   ScreenShot, Done : Boolean;
  1029.  
  1030. begin
  1031.   ScreenShot := ParamStr (1) = '--screenshot';
  1032.   if ParamCount <> Ord (ScreenShot) then
  1033.     begin
  1034.       RestoreTerminal (True);
  1035.       Writeln (StdErr, ParamStr (0), ': invalid argument `', ParamStr (Ord (ScreenShot) + 1), '''');
  1036.       Halt (1)
  1037.     end;
  1038.   CRTSavePreviousScreen;
  1039.   SetCRTUpdate (UpdateInput);
  1040.   MainPanel := GetActivePanel;
  1041.   CheckScreenSize;
  1042.   OrigScreenSize := ScreenSize;
  1043.   if ScreenShot then
  1044.     begin
  1045.       CursorShape := CursorBlock;
  1046.       NewWindow (6,      1,      1);
  1047.       NewWindow (2,      1, MaxInt);
  1048.       NewWindow (8, MaxInt,      1);
  1049.       NewWindow (5,      1,     27);
  1050.       KeyDemoKey (Ord ('f'));
  1051.       KeyDemoKey (246);
  1052.       KeyDemoKey (kbDown);
  1053.       NewWindow (3, MaxInt,     13);
  1054.       NewWindow (4, MaxInt,     31);
  1055.       NewWindow (7, MaxInt, MaxInt);
  1056.       NewWindow (9, MaxInt,     33);
  1057.       NewWindow (0,      1,      2);
  1058.       NewWindow (1,      1,     14);
  1059.       ActivateCursor;
  1060.       OpenWindow
  1061.     end
  1062.   else
  1063.     NewWindow (0, 3, 2);
  1064.   Done := False;
  1065.   repeat
  1066.     ActivateCursor;
  1067.     Key := GetKey (- 1);
  1068.     case LoCaseKey (Key) of
  1069.       Ord ('3'), kbF3  : OpenWindow;
  1070.       Ord ('4'), kbF4  : CloseWindow;
  1071.       Ord ('5'), kbF5  : PreviousWindow;
  1072.       Ord ('6'), kbF6  : NextWindow;
  1073.       Ord ('7'), kbF7  : MoveWindow;
  1074.       Ord ('8'), kbF8  : ResizeWindow;
  1075.       Ord ('q'), kbEsc,
  1076.       kbAltEsc :         Done := True;
  1077.       else
  1078.         if WindowList <> nil then
  1079.           with WindowList^, WindowTypes [WindowType] do
  1080.             if @KeyProc <> nil then
  1081.               begin
  1082.                 TextColor (Color);
  1083.                 TextBackground (Background);
  1084.                 KeyProc (Key)
  1085.               end
  1086.     end
  1087.   until Done
  1088. end.
  1089.